Ruby 的可靠性并非偶然;它是一种 结构化的纪律 建立在“尽早测试、经常测试”理念之上。通过在编写功能代码的同时编写单元测试,我们将调试从令人沮丧的 代码考古 转变为精确、实时的逻辑验证。
1. 单元测试范式
使用 Test::Unit 框架,我们将逻辑封装在 Test::Unit::TestCase中。以 test_ 开头的方法充当独立的实验室,对代码的各个单元进行探测、检查和验证。
2. 断言机制
断言是代码中的逻辑闸门。 assert_equal(预期值, 实际值) 将你的意图与实际情况进行比较。如果两者不匹配,测试就会失败,从而清晰地指出需要修复的具体行。
3. 命名以支持可扩展性
一致性至关重要。单个测试文件使用 tc_ (测试用例)前缀,而集合或套件则使用 ts_ (测试套件)前缀,确保随着代码库的增长,仍能保持良好的可导航性。
main.py
TERMINALbash — 80x24
> Ready. Click "Run" to execute.
>
QUESTION 1
In the
Test::Unit framework, which naming convention is required for a method to be automatically executed as a test?The method must end with
_test.The method must be named
verify_logic.The method must start with
test_.The method must be inside a
setup block.✅ Correct!
Correct! Ruby's test runner looks for methods starting with 'test_' to identify test cases.❌ Incorrect
The test runner specifically identifies methods starting with the prefix 'test_'.QUESTION 2
What is the primary difference between a file named
tc_orders.rb and ts_app.rb?tc_ is for C++ code; ts_ is for Ruby.tc_ represents an individual Test Case; ts_ represents a Test Suite (collection).tc_ is used for local tests; ts_ is for server tests.There is no functional difference; it is purely aesthetic.
✅ Correct!
Exactly. 'tc' stands for Test Case, while 'ts' stands for Test Suite, which usually requires multiple test cases.❌ Incorrect
The prefix 'tc' is for individual files containing test cases, while 'ts' is for suites that group those files together.QUESTION 3
Why does
assert_equal take two arguments?To compare the 'expected' value with the 'actual' result.
To define the minimum and maximum execution time.
To specify the class name and the method name.
To allocate memory for the test results.
✅ Correct!
Yes. It uses both to provide detailed error messages (e.g., 'Expected A, but got B').❌ Incorrect
Assertions compare your intended outcome (expected) against the code's output (actual).QUESTION 4
What happens if a test fails in the middle of a suite?
The entire computer restarts.
Ruby skips the rest of the file and deletes the log.
The test runner reports the failure and continues to the next test method.
The Ruby interpreter enters an infinite loop.
✅ Correct!
Test runners are designed to report failures while still attempting to run all other tests for maximum visibility.❌ Incorrect
Failures are reported as they happen, but the runner continues to execute remaining tests.QUESTION 5
Which Ruby library must be required to use
Test::Unit::TestCase?require 'debug'require 'test/unit'require 'benchmark'require 'roman'✅ Correct!
Correct. test/unit is the standard library for unit testing in the Pragmatic Programmer's era of Ruby.❌ Incorrect
You must require 'test/unit' to access the TestCase class and assertion methods.Case Study: The 'Archaeology' of Fred's Bug
Applying Unit Testing Principles to Legacy Code
Fred is working on a complex financial system. He spends three days writing a large feature, only to find a bug on day four. He now has to search through 2,000 lines of code to find the error, a process he calls 'code archaeology.'
Q
1. If Fred had unit tested his code as he wrote it, what two specific benefits would he have gained regarding bug detection?
Solution:
First, the unit test would have caught the logic error immediately while the implementation was fresh in his mind. Second, since the test would have targeted only the handful of lines he had just written, he would have identified the bug instantly without having to search through the entire 2,000-line codebase.
First, the unit test would have caught the logic error immediately while the implementation was fresh in his mind. Second, since the test would have targeted only the handful of lines he had just written, he would have identified the bug instantly without having to search through the entire 2,000-line codebase.
Q
2. In the Roman numeral example provided, the second assertion failed. What does the error message tell the developer about the code's behavior?
Solution:
The error message identifies that the assertion expected 'ix' but the code actually returned 'iiiiiiiii'. This reveals that the logic is currently only capable of handling unit increments ('i') and fails to implement the subtraction or grouping logic required for symbols like 'x' or 'v'.
The error message identifies that the assertion expected 'ix' but the code actually returned 'iiiiiiiii'. This reveals that the logic is currently only capable of handling unit increments ('i') and fails to implement the subtraction or grouping logic required for symbols like 'x' or 'v'.